/**
 * 1,Promise 是一个类，在执行这个类时，需要传递一个执行器进去，执行器会立即执行。
 * 2，Promise中有三种状态 分别是 成功fulfilled 失败rejected 等待pending(一般写入异步)
 *    pending->fulfilled
 *    pending->rejected
 *    一旦确定状态就不能在更改了。
 * 3，resolve和reject函数是用来改变状态的
 * 
 * 4，then方法内部做的事情就是判断状态是成功，还是失败，若果是成功状态就掉用成功的回调，失败就调用失败的回调 then方法是被定义在原型对象中的
 * 5，then成功回调有一个参数 表示成功之后的值 then失败回调有一个参数 表示失败后的原因
 * 6，同一个promise对象下面的then方法是可以被调多次的,即链式调用
 * 7，then方法是可以被链式调用的，后面的then方法的回调函数拿到值的是上一个then方法的回调函数的返回值
 * 8，then方法里面的
 * 
 */
const PENDING = 'pending'//防止值被更改。
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
  constructor(executor) {
    try {//捕获异常executor error
      executor(this.resolve, this.reject)
    } catch (error) {
      this.reject(error)
    }
  }
  status = PENDING
  value = undefined
  reason = undefined
  successCallback = []//成功回调的队列
  failCallback = []//失败回调的队列
  static resolve (value) {
    // if (value instanceof this.constructor) return value//this.constructor等价于MyPromies这个类
    // return new this.constructor((resolve) => { resolve(value) })
    if (value instanceof MyPromise) return value
    // 如果是值就返回一个promise对象，并返回值
    return new MyPromise(resolve => resolve(value))
  }
  resolve = value => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value//记录成功原因
    while (this.successCallback.length) { this.successCallback.shift()() }//循环执行所有的成功回调函数
  }
  reject = reason => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason//记录失败原因
    while (this.failCallback.length) { this.failCallback.shift()() }//循环执行所有的成功回调函数
  }
  then (successCallback, failCallback) {
    successCallback = successCallback ? successCallback : value => value
    failCallback = failCallback ? failCallback : reason => { throw reason }
    let newPromise = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        setTimeout(() => {//需要使用异步才能拿到newPromise(处理异步情况)
          try {//捕获then里面的异常
            let res = successCallback(this.value)//传递成功的原因
            /**
             * 链式调用
             * 判断返回的值是promise对象还是普通值。
             * 普通值，直接调用resolve
             * promise对象，查看promise的返回结果决定使用resolve还是reject
             */
            resolvePromise(newPromise, res, resolve, reject)
          } catch (err) {
            reject(err)
          }
        }, 0)
      } else if (this.status === REJECTED) {
        setTimeout(() => {//需要使用异步才能拿到newPromise(处理异步情况)
          try {
            let res = failCallback(this.reason)//传递失败的原因
            resolvePromise(newPromise, res, resolve, reject)
          } catch (err) {
            reject(err)
          }
        }, 0)
      }
      else {//等待状态（异步）
        // 将成功和失败回调都分别存贮对应数组中去
        this.successCallback.push(() => {
          setTimeout(() => {//需要使用异步才能拿到newPromise(处理异步情况)
            try {//捕获then里面的异常
              let res = successCallback(this.value)//传递成功的原因
              /**
               * 链式调用
               * 判断返回的值是promise对象还是普通值。
               * 普通值，直接调用resolve
               * promise对象，查看promise的返回结果决定使用resolve还是reject
               */
              resolvePromise(newPromise, res, resolve, reject)
            } catch (err) {
              reject(err)
            }
          }, 0)
        })
        this.failCallback.push(() => {
          setTimeout(() => {//需要使用异步才能拿到newPromise(处理异步情况)
            try {
              let res = failCallback(this.reason)//传递失败的原因
              resolvePromise(newPromise, res, resolve, reject)
            } catch (err) {
              reject(err)
            }
          }, 0)
        })
      }
    })
    return newPromise
  }
  finally (callback) {//then方法的一个特例。
    return this.then(
      // 把callback调用之后返回的promise传递过去，并且执行promise，且在成功之后返回value
      // 失败之后调用的then方法，然后把失败的原因返回出去。
      value => this.constructor.resolve(callback()).then(() => value),
      reason => this.constructor.resolve(callback()).then(() => { throw reason })
    )
  }
}
function resolvePromise (newPromise, res, resolve, reject) {
  if (res === newPromise) {//当.then里面返回实例本身时，代码会报错。然后就会走reject
    return reject(new TypeError('Chaining cycle detected for #<promise>'))
  }
  if (res instanceof MyPromise) {
    res.then(resolve, reject)//是promise对象继续传递resolve或reject回调函数下去。
  } else {
    resolve(res)
  }
}
// module.exports = MyPromise

// function p1 () {
//   return new MyPromise((resolve, reject) => {
//     setTimeout(() => {
//       resolve('p1')
//     }, 2000)
//   })
// }
// Promise.resolve(100).then(value => console.log(value))
// Promise.resolve(p1()).then(value => console.log(value))

function p1 () {
  return new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve('p1')
    }, 2000)
  })
}
function p2 () {
  return new MyPromise((resolve, reject) => {
    reject('p2 reject')
  })
}
p2().finally(() => {
  console.log('finallyp2')
  return p1()
}).then(value => {
  console.log(value)
}, reason => {
  console.log(reason)
})